using System;
using System.Diagnostics;
using System.Runtime.Remoting;
using System.Collections.Generic;
using CookComputing.XmlRpc;

namespace MyXmlRPCRemote
{
	public class Service : MarshalByRefObject 
	{
		private Dictionary<int, Command> m_Commands;
		private Layout m_Layout;
		
		public Service()
		{
			m_Commands = new Dictionary<int, Command>();
			m_Layout = new Layout();
		}
		
		public override object InitializeLifetimeService()
		{
			return null;
		}  
		
		public void AddCommands(Dictionary<int, Command> Commands)
		{
			m_Commands = Commands;
		}
		
		public void AddLayout(Layout TheLayout) {
			m_Layout = TheLayout;
		}
		
		private void ExecuteCommand(ProcessStartInfo ProcessInfo) {
			ProcessInfo.CreateNoWindow = true; 
			ProcessInfo.UseShellExecute = false;
			Process Proc = Process.Start(ProcessInfo);
			Proc.WaitForExit(1000);
			Proc.Close();
		}
		
		private String[] ExecuteListCommand(ProcessStartInfo ProcessInfo, String Separator) {
			Process p = new Process();
			p.StartInfo.UseShellExecute = false;
			p.StartInfo.RedirectStandardOutput = true;
			p.StartInfo.FileName = ProcessInfo.FileName;
			p.StartInfo.Arguments = ProcessInfo.Arguments;
			p.Start();
			string output = p.StandardOutput.ReadToEnd();
			p.WaitForExit();
			return output.Split(Separator.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
		}
		
		[XmlRpcMethod("MyXmlRPCRemote.CallCommand", 
		              Description="Call the specified command")] 
  		public void CallCommand(int CommandID)
		{
			ProcessStartInfo ProcessInfo;
			ProcessInfo = m_Commands[CommandID].CommandProcessInfo;
			ExecuteCommand(ProcessInfo);
  		}
		
		/// <summary>
		/// call a command with one argument.
		/// %1 will be replaces by the argument.
		/// </summary>
		/// <param name="CommandID">
		/// A <see cref="System.Int32"/>
		/// </param>
		/// <param name="Arg">
		/// A <see cref="String"/>
		/// </param>
		[XmlRpcMethod("MyXmlRPCRemote.CallCommandArg", 
		              Description="Call the specified command")] 
  		public void CallCommandArg(int CommandID, String Arg)
		{
			ProcessStartInfo ProcessInfo = new ProcessStartInfo();
			ProcessInfo.FileName = m_Commands[CommandID].CommandProcessInfo.FileName;
			ProcessInfo.Arguments = m_Commands[CommandID].CommandProcessInfo.Arguments;
			ProcessInfo.Arguments = ProcessInfo.Arguments.Replace("%1", Arg);
			ExecuteCommand(ProcessInfo);
  		}
		
		[XmlRpcMethod("MyXmlRPCRemote.GetList", 
		              Description="Call the specified command that returns a list")] 
  		public String[] GetList(int CommandID)
		{
			ProcessStartInfo ProcessInfo;		
			ProcessInfo = m_Commands[CommandID].ListProcessInfo;
			return ExecuteListCommand(ProcessInfo, m_Commands[CommandID].Separator);
  		}
		
		[XmlRpcMethod("MyXmlRPCRemote.GetLayout", 
		              Description="Get the UI layout")] 
		public Layout GetLayout() {
				return m_Layout;
		}
	}
	
	public struct Layout {
		public LayoutRow[] Rows;
		public int Height {
			get {
				int nHeight = 0;
				foreach (LayoutRow Row in Rows) {
					foreach	(LayoutElement Element in Row.Elements) {
						nHeight += Element.Height;	
					}
				}
				return nHeight;
			}
		}
	}
	
	public struct LayoutRow {
		public LayoutElement[] Elements;
	}
	
	public struct LayoutElement {
		public String Label;
		public int CommandID;
		public int Type;		// button 1 or list 2
		public int Height;
	}
	
	/// <summary>
	/// the representation of the ui control element
	/// in case of type 2, a list, the CallCommandArg should be executed with
	/// then we take the text of the list item and use it as argument
	/// </summary>
	public struct Command {
		public ProcessStartInfo CommandProcessInfo;
		public ProcessStartInfo ListProcessInfo;
		public int CommandType;
		public String Separator;
	}
}

